package com.mall.group_booking.listener;

import com.alibaba.fastjson.JSONObject;
import com.mall.constant.enums.BookingRootStatus;
import com.mall.constant.enums.OrderStatus;
import com.mall.constant.strings.ConstantStrings;
import com.mall.constant.strings.MapMsg;
import com.mall.entity.bargain.BgOrder;
import com.mall.entity.groupbooking.GbRoot;
import com.mall.group_booking.entity.GbItemVo;
import com.mall.group_booking.entity.GbRecordVo;
import com.mall.group_booking.feign.OrderFeign;
import com.mall.group_booking.service.BookingRootService;
import com.mall.utils.MatcherUtil;
import org.redisson.Redisson;
import org.redisson.api.RLock;
import org.redisson.api.RMap;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.connection.Message;
import org.springframework.data.redis.listener.KeyExpirationEventMessageListener;
import org.springframework.data.redis.listener.RedisMessageListenerContainer;
import org.springframework.jms.core.JmsMessagingTemplate;
import org.springframework.stereotype.Component;

import java.util.concurrent.TimeUnit;

/**
 * @author White
 * @version 1.0
 * @email 616769721@qq.com
 * @date 2021/7/20 14:27
 */
@Component
public class IfOrderIdExpirationListener extends KeyExpirationEventMessageListener {

    @Autowired
    private Redisson redisson;

    @Autowired
    private OrderFeign orderFeign;

    @Autowired
    private JmsMessagingTemplate jmsMessagingTemplate;

    @Autowired
    private BookingRootService bookingRootService;


    public IfOrderIdExpirationListener(RedisMessageListenerContainer listenerContainer) {
        super(listenerContainer);
    }

    /**
     * 针对redis数据失效事件，进行数据处理
     * @param message 信息
     * @param pattern 样式
     */
    @Override
    public void onMessage(Message message, byte[] pattern) {
        // message.toString()可以获取失效的key
        //正则比较过期的key是否为拼团相关信息
        if (!MatcherUtil.match(ConstantStrings.IF_BOOKING_ORDER_ID_MATCH, message.toString())) {
            System.out.println(message);
            //结束处理
            return;
        }
        //解析字符串
        String[] keys = message.toString().split("ID:");
        System.out.println("ID:" + keys[1]);
        //如果监听到拼团过期标志
        if (MatcherUtil.match(ConstantStrings.IF_BOOKING_ROOT_ID_MATCH, message.toString())){
            RMap<Integer, GbRoot> rootMap = redisson.getMap(MapMsg.BOOKING_ROOT_REDIS_MAP);
            RMap<Long, GbItemVo> itemMap = redisson.getMap(MapMsg.BOOKING_ITEM_REDIS_MAP);
            Integer rootId=Integer.parseInt(keys[1]);
            //获取团
            GbRoot gbRoot =rootMap.get(rootId);
            //根据商品id上锁，同时一个商品只有一个操作
            RLock lock = redisson.getLock(gbRoot.getSpecItemId().toString());
            try{
                lock.lock(5, TimeUnit.SECONDS);
                //获取商品
                GbItemVo gbItemVo = itemMap.get(gbRoot.getSpecItemId());
                //自动将参团人数拉满
                gbRoot.setJoinCount(gbItemVo.getCountPerson());
                //修改团状态
                gbRoot.setStatus(BookingRootStatus.completed.getCode());
                //删除redis中成功的团
                rootMap.remove(gbRoot.getId());
                //更新到数据库
                bookingRootService.updateBookingRoot(gbRoot);
                //成团数量+1
                gbItemVo.setSuccessCount(gbItemVo.getSuccessCount()+1);
                //更新到redis中
                itemMap.put(gbItemVo.getSpecItemId(),gbItemVo);
            }finally {
                lock.unlock();
            }
            //结束处理
            return;
        }
        //远程调用查询改订单
        BgOrder bgOrder = orderFeign.findOne(Long.parseLong(keys[1]));
        //获取订单号
        Long orderItemId = bgOrder.getOrderItemId();
        //从redis中获取拼团商品map和团map
        RMap<Integer, GbRoot> rootMap = redisson.getMap(MapMsg.BOOKING_ROOT_REDIS_MAP);
        RMap<Long, GbItemVo> itemMap = redisson.getMap(MapMsg.BOOKING_ITEM_REDIS_MAP);
        //根据订单的具体商品id上锁，
        RLock itemSpecLock = redisson.getLock(bgOrder.getItemSpecId().toString());
        //如果为拼团团长单
        if (MatcherUtil.match(ConstantStrings.IF_BOOKING_ROOT_ORDER_ID_MATCH, message.toString())) {
            try {
                itemSpecLock.lock(5, TimeUnit.SECONDS);
                //通过订单详情的拼团团id获取团map中的对象
                GbRoot gbRoot = rootMap.get(Integer.parseInt(orderItemId.toString()));
                //设置团状态为已失效
                gbRoot.setStatus(BookingRootStatus.BECAME_INVALID.getCode());
                //将状态更新到数据库中
                jmsMessagingTemplate.convertAndSend("doBookingRootInvalid", JSONObject.toJSONString(gbRoot));
                //将该团从redis中删除
                rootMap.remove(gbRoot.getId());
                //获取需要回滚的商品对象
                GbItemVo gbItemVo = itemMap.get(gbRoot.getSpecItemId());
                //回归销量
                gbItemVo.setLimitSurplus(gbItemVo.getLimitSurplus() + 1);
                //更新到redis中
                itemMap.put(gbItemVo.getSpecItemId(), gbItemVo);
            } finally {
                itemSpecLock.unlock();
            }
        }
        //如果为拼团普通单
        // if (MatcherUtil.match(ConstantStrings.IF_BOOKING_RECORD_ORDER_ID_MATCH, message.toString()))
        else {
            RMap<Long, GbRecordVo> recordMap = redisson.getMap(MapMsg.BOOKING_RECORD_REDIS_MAP);
            try {
                itemSpecLock.lock(5, TimeUnit.SECONDS);
                //获取redis中的记录数据
                GbRecordVo gbRecordVo = recordMap.get(orderItemId);
                //删除无效参团记录
                recordMap.remove(orderItemId);
                //通过拼单距离中的团id获取团map在的对象
                GbRoot gbRoot = rootMap.get(gbRecordVo.getRootId());
                //该团参与人数回滚
                gbRoot.setJoinCount(gbRoot.getJoinCount()-1);
                //更新到redis中
                rootMap.put(gbRoot.getId(), gbRoot);
                //获取需要回滚的商品对象
                GbItemVo gbItemVo = itemMap.get(gbRecordVo.getItemId());
                //回归销量
                gbItemVo.setLimitSurplus(gbItemVo.getLimitSurplus() + 1);
                //更新到redis中
                itemMap.put(gbItemVo.getSpecItemId(), gbItemVo);
            } finally {
                itemSpecLock.unlock();
            }
        }
        //更新数据库中过期订单的状态
        orderFeign.updateOrderStatus(bgOrder.getId(), OrderStatus.BECAME_NVALID.getCode());
    }
}
